﻿using Hydrogen.MathExt.Expression.Functions.Operators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Hydrogen.MathExt.Expression
{
    /// <summary>
    /// 使用调度场算法将中缀表达式转换为逆波兰表达式<br/>
    /// 处理运算符优先级和函数调用<br/>
    /// 处理括号和逗号（函数参数分隔符）<br/>
    /// </summary>
    internal class RPNConverter
    {
        public static List<Token> ConvertToRPN(List<Token> tokens)
        {
            List<Token> output = new List<Token>();
            Stack<Token> operators = new Stack<Token>();

            foreach (Token token in tokens)
            {
                switch (token.Type)
                {
                    case TokenType.Number:
                    case TokenType.Constant:
                    case TokenType.Variable:
                        output.Add(token);
                        break;

                    case TokenType.Function:
                        operators.Push(token);
                        break;

                    case TokenType.Comma:
                        while (operators.Count > 0 && operators.Peek().Value != ExpressionHelper.LEFT_PARENTHESIS)
                        {
                            output.Add(operators.Pop());
                        }
                        break;

                    case TokenType.Operator:
                        while (operators.Count > 0 &&
                           operators.Peek().Type == TokenType.Operator &&
                           OperatorBinaryBase.GetPrecedence(token.Value) <= OperatorBinaryBase.GetPrecedence(operators.Peek().Value))
                        {
                            output.Add(operators.Pop());
                        }
                        operators.Push(token);
                        break;

                    case TokenType.LeftParenthesis:
                        operators.Push(token);
                        break;

                    case TokenType.RightParenthesis:
                        while (operators.Count > 0 && operators.Peek().Value != ExpressionHelper.LEFT_PARENTHESIS)
                        {
                            output.Add(operators.Pop());
                        }
                        if (operators.Count > 0 && operators.Peek().Value == ExpressionHelper.LEFT_PARENTHESIS)
                        {
                            operators.Pop();
                        }

                        if (operators.Count > 0 && operators.Peek().Type == TokenType.Function)
                        {
                            output.Add(operators.Pop());
                        }
                        break;
                }
            }

            while (operators.Count > 0)
            {
                output.Add(operators.Pop());
            }

            return output;
        }
    }
}
